using Excel = Microsoft.Office.Interop.Excel;
using UCL.Powersource.Statistics;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.TeamFoundation;
using PowersourceUIToolkit;
using UCL.Powersource.TFS;
using System.Data;
using UCL.Powersource.Exports;


namespace UCL.Powersource.ViewModels
{
    /// <summary>
    /// MainViewModel for powersource
    /// </summary>
    [Export(typeof(PowersourceMainViewModel))]
    public class PowersourceMainViewModel : ViewModelBase
    {



        /// <summary>
        /// States of the ViewModel when TFS is Connected and Disconnected, which are then populated to View as VisualStates
        /// </summary>
        public enum ViewModelStates
        {
            Disconnected,
            Connected
        }


        /// <summary>
        /// The ViewModel states Changed as Disconnected or Connected
        /// </summary>
        public class ViewConfiguration : PropertyChangedBase
        {
            private readonly PowersourceMainViewModel VM;
            internal ViewConfiguration(PowersourceMainViewModel vm)
            {
                VM = vm;
            }

            ViewModelStates _ViewModelState = ViewModelStates.Disconnected;     // The ViewModel state is Disconnected: TFS is not connected

            /// <summary>
            /// Change the VisualStates depending on the the state of the ViewModel
            /// </summary>
            public ViewModelStates ViewModelState
            {
                get { return _ViewModelState; }
                private set { if (value == _ViewModelState) return; else { _ViewModelState = value; NotifyOfPropertyChange(() => ViewModelState); } }
            }

            internal void ViewModelState_Recalculate()      //Recalculate the VisualStates of the ViewModel
            {
                if (VM.IsTFSConnected) ViewModelState = ViewModelStates.Connected; //If TFS is connected then VisualState Connected
                else
                    ViewModelState = ViewModelStates.Disconnected;      //otherwise VisualState Disconnected
            }

            internal void UpdateConfiguration()     //Recalculate the VisualState when the ViewModel is loaded in order to update configuration
            {
                if (VM.IsLoaded)
                {
                    ViewModelState_Recalculate();
                }
            }

        }

        /// <summary>
        /// ConfigurationCollection of the View
        /// </summary>
        public readonly ViewConfiguration ViewConfig;

        public PowersourceMainViewModel()
            : base()
        {
            ViewConfig = new ViewConfiguration(this);
            Initialized += PowersourceMainViewModel_Initialized;
            Activated += PowersourceMainViewModel_Activated;
        }

        void PowersourceMainViewModel_Activated(object sender, EventArgs e)     //Update the configuration of the View when the MainViewModel is activated
        {
            ViewConfig.UpdateConfiguration();
        }

        void PowersourceMainViewModel_Initialized(object sender, EventArgs e)   //Update the configuration of the View when the MainViewModel is initialized
        {
            ViewConfig.UpdateConfiguration();
        }

        
        IPowersourceExt PowersourceExt
        {
            get { return PowersourceConnector.GetExtensibilityPoint(); }
        }

        protected override bool OnInitializing()
        {
            var PowersourceExt = PowersourceConnector.GetExtensibilityPoint();
            var smq = PowersourceExt.StatisticManager.StatisticManagerQueue;
            if(smq != null) smq.Initialize();
            var rmq = IoC.Get<IRemoteBuilderQueue>();
            if (rmq != null) rmq.Initialize();
            return true;
        }

        protected override bool OnActivating()
        {
            Log.TraceMethod();
            CurrentTfsTeamProjectCollection_Recalculate();  //Recalculate the current tfs project collection when the MainViewModel is Activated
            return true;
        }

        protected override bool OnDeactivating()
        {
            Log.TraceMethod();
            PackageConfigurationLoader.Save(PackageConfiguration, TFSConfigFileName); //Save the TFS stat project collection configurations when the MainViewModel is Deactivated
            //SaveTfsTeamProjectCollectionConfigurations(TFSConfigFileName, PackageConfiguration);
            return true;
        }

        protected override void OnDisposing()
        {
            if (this.TFSExt != null)
            {
                this.TFSExt.ProjectContextChanged -= _tfsExt_ProjectContextChanged;
            }

            if (_TfsTeamCollectionConfigurations != null)
            {
                PackageConfigurationLoader.Save(PackageConfiguration, TFSConfigFileName); //Save the TFS stat project collection configurations when the MainViewModel is Deactivated
                //SaveTfsTeamProjectCollectionConfigurations(TFSConfigFileName, PackageConfiguration);
            }
        }
        private string _Title = "Powersource 1.0.3";
        public string Title
        {
            get { return _Title; }
            private set
            {
                _Title = value;
                NotifyOfPropertyChange(() => Title);
            }
        }

        public void OpenReporting()
        {
            IViewModel reporting = ViewModelLocator.GetViewModel<ReportingViewModel>();
            if (!reporting.IsInitialized) reporting.Initialize();
            IUIManager ui = IoC.Get<IUIManager>();
            ui.ActivateViewModelInConductor(reporting, ui.GetConductorForViewModel(this));
        }

        public void OpenSettings()
        {
            IViewModel settings = ViewModelLocator.GetViewModel<SettingsViewModel>();
            if (!settings.IsInitialized) settings.Initialize();
            IUIManager ui = IoC.Get<IUIManager>();
            ui.ActivateViewModelInConductor(settings, ui.GetConductorForViewModel(this));
        }

        /// <summary>
        /// Method that invokes the VS Connect to TFS window 
        /// </summary>
        public void TryTFSConnect()
        {

            dte2.ExecuteCommand("Team.ConnecttoTeamFoundationServer");
            NotifyOfPropertyChange(() => IsTFSConnected);
            ViewConfig.ViewModelState_Recalculate();    //Recalculate the VisualState

        }

        public void ConnectToTFS(string CollectionURI, string TeamUri = null)
        {
            var tfscol = IoC.Get<ITfsTeamProjectCollectionFactory>().GetTeamProjectCollection(new Uri(CollectionURI));
            IoC.Get<IVSEnv>().SetTfsContext(tfscol, TeamUri, IsTFSConnected);
        }

        public void DisconnectFromTFS()
        {
            var ivsEnv = IoC.Get<IVSEnv>();
            Log.DebugMethod("ivsEnv = {0}", ivsEnv);
            ivsEnv.SetTfsContext(null, null, IsTFSConnected);
        }

        /// <summary>
        /// Method that checks if VS is connected to TFS, and if not invokes the connection window
        /// </summary>
        public void StartUpTFSConnect()
        {
            if (!IsTFSConnected)
            {
                TryTFSConnect();
            }

        }

        /// <summary>
        /// Method that returns true if VS is currently connected to a TFS and false if itForFE is not
        /// </summary>

        public bool IsTFSConnected
        {
            get
            {
                if (TFSExt == null) return false;
                else
                    if (TFSExt.ActiveProjectContext == null) return false;
                    else

                        if (TFSExt.ActiveProjectContext.DomainName == null)     //Server is disconnected
                        {
                            return false;
                        }
                        else
                        {
                            return true;
                        }
            }
        }


        private ITeamFoundationServerExt _tfsExt;

        /// <summary>
        /// Provides an access to TFS automation object through which we are able to get
        /// current active project Context and listen to <see cref="TeamFoundationServerExt.ProjectContextChanged"/>
        /// </summary>
        public ITeamFoundationServerExt TFSExt
        {
            get
            {
                if (_tfsExt == null)    //_tfsExt is a singleton so if itForFE does not exist yet we create itForFE and attach to ProjectContextChanged event
                {

                    _tfsExt = dte2.TeamFoundationServerExt;
                    _tfsExt.ProjectContextChanged += _tfsExt_ProjectContextChanged;

                }
                return _tfsExt;
            }
        }

        /// <summary>
        /// Recalculate the current tfs stat project collection if the tfs stat project collection changed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _tfsExt_ProjectContextChanged(object sender, EventArgs e)
        {
            CurrentTfsTeamProjectCollection_Recalculate();

            //NotifyOfPropertyChange(() => IsTFSConnected);
            //throw new NotImplementedException();
        }


        /// <summary>
        /// The top-level object in the Visual Studio automation object model,
        /// where EnvDTE80 contains the objects and members for Visual Studio core automation.
        /// It extends and compliments the functionality provided by EnvDTE
        /// </summary>
        //public EnvDTE80.DTE2 dte2
        public IVSEnv dte2
        {
            get
            {
                return IoC.Get<IVSEnv>();
            }

        }


        private ObservableCollection<ITfsTeamProjectConfiguration> _CurrentTfsTeamProjectConfigurations;

        /// <summary>
        /// Collection of the tfs stat project configurations of the current stat project collection
        /// </summary>
        public ObservableCollection<ITfsTeamProjectConfiguration> CurrentTfsTeamProjectConfigurations
        {
            get { return _CurrentTfsTeamProjectConfigurations; }
            private set
            {
                if (_CurrentTfsTeamProjectConfigurations == value) return;
               
                _CurrentTfsTeamProjectConfigurations = value;
                NotifyOfPropertyChange(() => CurrentTfsTeamProjectConfigurations);
            }
        }


        #region CollectionTitle

        /// <summary>
        /// Field storage for property CollectionTitle
        /// </summary>
        private string _CollectionTitle = "Not connected";

        /// <summary>
        /// Property CollectionTitle. TODODOC: Insert appropriate summary here
        /// </summary>
        public string CollectionTitle
        {
            get { return _CollectionTitle; }
            set
            {
                if (_CollectionTitle == value) return;
                _CollectionTitle = "Connected to: " + value;
                CollectionTitle_RecalculateDependencies();
            }
        }

        private void CollectionTitle_RecalculateDependencies()
        {
            //Recalculate all properties here

            //NotifyOfPropertyChange is usually placed as last statement - first change all dependencies and then fire property change
            NotifyOfPropertyChange(() => CollectionTitle);
        }

        private void CollectionTitle_Recalculate()
        {
            _CollectionTitle = "Not connected";
            //Insert your code here

            CollectionTitle_RecalculateDependencies();
        }

        #endregion


        ITfsTeamProjectCollectionConfiguration _CurrentTfsTeamProjectCollectionConfiguration;

        /// <summary>
        /// Get the current stat project collections' configurations
        /// </summary>
        public ITfsTeamProjectCollectionConfiguration CurrentTfsTeamProjectCollectionConfiguration
        {
            get { return _CurrentTfsTeamProjectCollectionConfiguration; }
            private set
            {
                if (_CurrentTfsTeamProjectCollectionConfiguration == value) return;
                // if (_CurrentTfsTeamProjectCollectionConfiguration != null)
                //{
                //    _CurrentTfsTeamProjectCollectionConfiguration
                //}
                _CurrentTfsTeamProjectCollectionConfiguration = value;
                CurrentTfsTeamProjectCollectionConfiguration_RecalculateDependencies();
            }
        }

        private void CurrentTfsTeamProjectCollectionConfiguration_RecalculateDependencies()
        {
            if (CurrentTfsTeamProjectCollectionConfiguration == null)       //If there is no current (active) stat project collection configurations then there is no current tfs stat project configurations 
            {
                CurrentTfsTeamProjectConfigurations = null;
                CollectionTitle_Recalculate();
            }
            else
            {
                CurrentTfsTeamProjectConfigurations = new ObservableCollection<ITfsTeamProjectConfiguration>(CurrentTfsTeamProjectCollectionConfiguration);   //otherwise recalculate the depedencies of the current tfs stat project collection configuration
                CollectionTitle = CurrentTfsTeamProjectCollectionConfiguration.Uri;
            }
            NotifyOfPropertyChange(() => CurrentTfsTeamProjectCollectionConfiguration);
        }

        public void RefreshCurrentTfsTeamProjectCollectionConfiguration()
        {
            CurrentTfsTeamProjectCollection_RecalculateDependencies();
            CurrentTfsTeamProjectCollectionConfiguration_RecalculateDependencies();
        }

        IPackageConfiguration _TfsTeamCollectionConfigurations;

        /// <summary>
        /// Collection of the tfs stat project collection configurations
        /// </summary>
        public IPackageConfiguration PackageConfiguration
        {
            get { return _TfsTeamCollectionConfigurations; }
            set
            {
                if (_TfsTeamCollectionConfigurations == value) return;
                if (value == null && _TfsTeamCollectionConfigurations != null)
                {
                    PackageConfigurationLoader.Save(PackageConfiguration, TFSConfigFileName); //Save the TFS stat project collection configurations when the MainViewModel is Deactivated
                    //SaveTfsTeamProjectCollectionConfigurations(TFSConfigFileName, PackageConfiguration);
                }
                _TfsTeamCollectionConfigurations = value;
                NotifyOfPropertyChange(() => PackageConfiguration);
            }
        }

        internal const string TFSConfigFileName = "TFSConfig.xml";

        ITfsTeamProjectCollection _CurrentTfsTeamCollection;

        /// <summary>
        /// Get the current tfs stat project collection
        /// </summary>
        public ITfsTeamProjectCollection CurrentTfsTeamProjectCollection
        {
            get
            {
                return _CurrentTfsTeamCollection;
            }
            private set
            {
                if (_CurrentTfsTeamCollection == value) return;
                _CurrentTfsTeamCollection = value;
                CurrentTfsTeamProjectCollection_RecalculateDependencies();
                NotifyOfPropertyChange(() => CurrentTfsTeamProjectCollection);
            }


        }

        private void CurrentTfsTeamProjectCollection_RecalculateDependencies()
        {
            if (PackageConfiguration == null)
            {
                PackageConfiguration = PackageConfigurationLoader.Load(TFSConfigFileName);
                //PackageConfiguration = LoadTfsTeamProjectCollectionConfiguration(TFSConfigFileName);
            }
            if (CurrentTfsTeamProjectCollection != null)        //If there is no current (active) tfs stat project collection then merge 
            {
                PackageConfiguration.MergeWithCollection(CurrentTfsTeamProjectCollection);
                var tfsColSet = PackageConfiguration.TFSTeamCollectionConfigurations.Single(a => a.IsConnectedTo(CurrentTfsTeamProjectCollection));
                CurrentTfsTeamProjectCollectionConfiguration = tfsColSet;
            }
            else
            {
                CurrentTfsTeamProjectConfigurations = null;
                CurrentTfsTeamProjectCollectionConfiguration = null;
            }
        }

        private void CurrentTfsTeamProjectCollection_Recalculate()
        {
            if (!IsTFSConnected)        //If tfs is not connected then there is no current tfs stat project collection
            {
                if (PackageConfiguration != null) PackageConfigurationLoader.Save(PackageConfiguration, TFSConfigFileName);
                CurrentTfsTeamProjectCollection = null;
                PackageConfiguration = null;
            }
            else          //otherwise get the domain uri of the current (active) project collection
            {
                CurrentTfsTeamProjectCollection = IoC.Get<ITfsTeamProjectCollectionFactory>().GetTeamProjectCollection(new Uri(TFSExt.ActiveProjectContext.DomainUri));
                
            }
            var cc = UIManager.GetViewConductor(this);
            if (cc != null && !this.IsActivated)
            {
                cc.ActivateViewModel(this);
            }
            ViewConfig.ViewModelState_Recalculate();
        }

        public void ComputeStatisticsForExport()
        {
            if (CurrentTfsTeamProjectConfigurations == null) return;
            var IPowersourceExt = PowersourceConnector.GetExtensibilityPoint();
            var stats = IPowersourceExt.StatisticManager.AvailableStatistics.Where(a => a.Value is WIStateStatisticsBase);
            var allTeams = CurrentTfsTeamProjectCollectionConfiguration.Where(a => a.IsChosen);
            var allTFs = CurrentTfsTeamProjectCollectionConfiguration.ProjectCollectionTimeFrames;
            if (stats == null || stats.Count() == 0) return;
            if (allTeams == null || allTeams.Count() == 0) return;
            if (allTFs == null || allTFs.Count() == 0) return;
            foreach (var stat in stats)
            {
                foreach (var team in allTeams)
                {
                    foreach (var tf in allTFs)
                    {
                        IPowersourceExt.StatisticManager.ResolveStatistic(stat.Value.Statistic_Guid, team, tf);
                    }
                }
            }
            PackageConfigurationLoader.Save(PackageConfiguration, TFSConfigFileName);
        }

        public void ExportToExcel()
        {
            ExportToExcelTeam();
            ExportToExcelTotal();
        }

        public void ExportToExcelTeam()
        {
            if (CurrentTfsTeamProjectConfigurations == null) return;
            var IPowersourceExt = PowersourceConnector.GetExtensibilityPoint();
            var stats = IPowersourceExt.StatisticManager.AvailableStatistics.Where(a => a.Value is WIStateStatisticsBase).Select(a => a.Value);
            var allTeams = CurrentTfsTeamProjectCollectionConfiguration.Where(a => a.IsChosen);
            var allTFs = CurrentTfsTeamProjectCollectionConfiguration.ProjectCollectionTimeFrames;
            if (stats == null || stats.Count() == 0) return;
            if (allTeams == null || allTeams.Count() == 0) return;
            if (allTFs == null || allTFs.Count() == 0) return;

            using (var ds = XLSExports.CreateTeam_TimeFrameCol_StatisticRowDataset(stats, allTeams, allTFs))
            {
                Excel.Application app = null;
                Excel.Workbook wb = null;
                var tableIndex = 0;
                try
                {

                    foreach (var team in allTeams)
                    {
                        var tableName = XLSExports.GetTableName(team);
                        var table = ds.Tables[tableName];
                        if (table == null)
                        {
                            Log.Error(null, "Table {0} for team {1} not available. Export skipped.", tableName, team.ToString());
                            continue;
                        }
                        var sht = XLSExports.GetNewTeamExport(team, team.UniqueName, app);
                        app = sht.Application;
                        wb = sht.Application.ActiveWorkbook;
                        XLSExports.ExportDataTableToRange(sht.Cells[10, 1], table, true);
                        wb.Save();
                        wb.Close(false);
                        wb = null;
                        tableIndex++;
                    }
                    XLSExports.Finish(app, wb, false);
                }
                catch (Exception exc)
                {
                    Log.Error(exc, "Export Team report thrown an exception");
                    XLSExports.FailsafeFinish(Log, app, wb, true);

                }

            }



            //var sht=XLSExports.GetNewTeamExport(stat,stat.UniqueName,app);




        }

        public void ExportToExcelTotal()
        {
            if (CurrentTfsTeamProjectConfigurations == null) return;
            var IPowersourceExt = PowersourceConnector.GetExtensibilityPoint();
            var stats = IPowersourceExt.StatisticManager.AvailableStatistics.Where(a => a.Value is WIStateStatisticsBase).Select(a => a.Value);
            var allTeams = CurrentTfsTeamProjectCollectionConfiguration.Where(a => a.IsChosen);
            var allTFs = CurrentTfsTeamProjectCollectionConfiguration.ProjectCollectionTimeFrames;
            if (stats == null || stats.Count() == 0) return;
            if (allTeams == null || allTeams.Count() == 0) return;
            if (allTFs == null || allTFs.Count() == 0) return;

            Log.DebugMethod("Preparing data");
            using (var ds = XLSExports.CreateTimeFrame_StatisticCol_TeamRowDataset(stats, allTeams, allTFs))
            {
                Log.DebugMethod("Starting export to XLS");
                Excel.Application app = null;
                Excel.Workbook wb = null;
                try
                {
                    var wsht = XLSExports.GetNewProfessorExport(CurrentTfsTeamProjectCollectionConfiguration, () => IPowersourceExt.StatisticManager.AvailableStatistics.Values, () => CurrentTfsTeamProjectCollectionConfiguration.ProjectCollectionTimeFrames);
                    app = wsht.Application;
                    wb = app.ActiveWorkbook;
                    XLSExports.ExportDataSetToWorksheet(wb, ds);
                    Log.DebugMethod("Finishing export to XLS");
                    XLSExports.Finish(app, wb, true,string.Format("Powersource-TotalExport-{0:yyMMdd}.xlsx",DateTime.Now));
                    Log.DebugMethod("Export to XLS done.");
                }
                catch (Exception exc)
                {

                    Log.Error(exc, "Exporting throw an exception. Failsafe closing and detaching");
                    XLSExports.FailsafeFinish(Log, app, wb, true);


                }
            }

        }


    }
}
